package cn.s1995.sloth.app.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.s1995.sloth.common.core.constant.enums.hint.Hint;
import cn.s1995.sloth.bizs.entity.Cart;
import cn.s1995.sloth.bizs.entity.Prod;
import cn.s1995.sloth.bizs.entity.Sku;
import cn.s1995.sloth.bizs.event.ShopCartEvent;
import cn.s1995.sloth.bizs.exception.BizException;
import cn.s1995.sloth.bizs.oo.dto.*;
import cn.s1995.sloth.bizs.oo.req.ChangeCartREQ;
import cn.s1995.sloth.bizs.service.CartService;
import cn.s1995.sloth.bizs.service.ProdService;
import cn.s1995.sloth.bizs.service.SkuService;
import cn.s1995.sloth.common.core.util.R;
import cn.s1995.sloth.common.security.util.SecurityUtils;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.apache.commons.compress.utils.Lists;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * CommonController
 *
 * @author Lex
 * @description 我的
 * @date 2023/12/23 17:14
 */
@RestController
@RequestMapping("/m/cart")
@RequiredArgsConstructor
@Tag(description = "CartController", name = "APP-购物车")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class ApiCartController {

    private final CartService cartService;
    private final ProdService prodService;
    private final SkuService skuService;
    private final ApplicationContext applicationContext;

    @ApiOperationSupport(order = 1)
    @Operation(summary = "获取购物车", description = "获取用户购物车信息，参数为用户选中的活动项数组,以购物车id为key")
    @PostMapping("/info")
    public R<List<ShopCartDTO>> getList(@RequestBody Map<Long, ShopGetCartDTO> cartIdShopCartParamMap) {
        Long userId = SecurityUtils.getUser().getId();

        // 更新满减活动
        if (MapUtil.isNotEmpty(cartIdShopCartParamMap)) {
            cartService.updateCartByShopCartParam(userId, cartIdShopCartParamMap);
        }

        // 拿到购物车的所有item
        List<ShopCartItemDTO> shopCartItems = cartService.getShopCartItems(userId);

        return R.ok(cartService.getShopCarts(shopCartItems));
    }

    @ApiOperationSupport(order = 2)
    @Operation(summary = "添加、修改用户购物车", description = "通过产品id(prodId)、skuId、店铺Id(shopId),添加/修改用户购物车产品，并传入改变的产品个数(num)，" +
            "当数量为正值时，增加产品数量，当数量为负值时，将减去产品的数量，当最终数量值小于0时，会将产品从购物车里面删除")
    @PostMapping("/change")
    public R changeCart(@Valid @RequestBody ChangeCartREQ req) {
        // 当数量为0时，不做改变
        if (req.getNum() == 0) {
            return R.ok();
            // throw new BizException(Hint.APP_CART_CHANGE_NUM);
        }

        Long userId = SecurityUtils.getUser().getId();
        List<ShopCartItemDTO> shopCartItems = cartService.getShopCartItems(userId);
        Prod prod = prodService.getProduct(req.getProdId());
        Sku sku = skuService.getSku(req.getSkuId());

        if (Objects.isNull(prod) || Objects.isNull(sku)) {
            throw new BizException(Hint.APP_PROD_NOT_SALE, prod.getName());
        }

        // 当产品状态不正常时，不能添加到购物车
        if (BooleanUtil.isFalse(prod.getIsSale()) || BooleanUtil.isFalse(sku.getIsSale()) || BooleanUtil.isTrue(sku.getIsDeleted())) {
            throw new BizException(Hint.APP_PROD_NOT_SALE, prod.getName());
        }
        for (ShopCartItemDTO shopCartItemDTO : shopCartItems) {
            if (Objects.equals(req.getSkuId(), shopCartItemDTO.getSkuId())) {
                Cart cart = new Cart();
                cart.setUid(userId);
                cart.setNum(req.getNum() + shopCartItemDTO.getProdNum());
                cart.setId(shopCartItemDTO.getCartId());

                // 防止购物车变成负数
                if (cart.getNum() <= 0) {
                    cartService.removeShopCartItemsByCartIds(userId, Collections.singletonList(cart.getId()));
                    return R.ok();
                }

                // 当sku实际库存不足时，不能添加到购物车
                if (sku.getActualStocks() < cart.getNum() && shopCartItemDTO.getProdNum() > 0) {
                    throw new BizException(Hint.APP_PROD_STOCKS_NOT_ENOUGH, sku.getProdName());
                }
                cartService.updateShopCartItem(cart);
                return R.ok();
            }
        }

        // 防止购物车已被删除的情况下,添加了负数的产品
        if (req.getNum() < 0) {
            throw new BizException(Hint.APP_CART_PROD_HAS_BENN_REMOVED);
        }
        // 当sku实际库存不足时，不能添加到购物车
        if (sku.getActualStocks() < req.getNum()) {
            throw new BizException(Hint.APP_PROD_STOCKS_NOT_ENOUGH, sku.getProdName());
        }
        // 前端没有传入shopId时，使用产品的shopId
        if (Objects.isNull(req.getShopId())) {
            req.setShopId(prod.getShopId());
        }

        // 所有都正常时
        cartService.addShopCartItem(req, userId);

        return R.ok();
    }

    @ApiOperationSupport(order = 3)
    @GetMapping("/prodCount")
    @Operation(summary = "获取购物车产品数量", description = "获取所有购物车产品数量")
    public R<Integer> prodCount() {
        Long userId = SecurityUtils.getUser().getId();
        List<ShopCartItemDTO> shopCartItems = cartService.getShopCartItems(userId);
        if (CollUtil.isEmpty(shopCartItems)) {
            return R.ok(0);
        }
        Integer totalCount = shopCartItems.stream().map(ShopCartItemDTO::getProdNum).reduce(0, Integer::sum);
        return R.ok(totalCount);
    }

    @ApiOperationSupport(order = 4)
    @GetMapping("/expiryProdList")
    @Operation(summary = "获取购物车失效产品信息", description = "获取购物车失效产品列表")
    public R<List<ShopCartExpiryItemDTO>> expiryProdList() {
        Long userId = SecurityUtils.getUser().getId();
        List<ShopCartItemDTO> shopCartItems = cartService.getShopCartExpiryItems(userId);
        // 根据店铺ID划分item
        Map<Long, List<ShopCartItemDTO>> shopCartItemDtoMap = shopCartItems.stream().collect(Collectors.groupingBy(ShopCartItemDTO::getShopId));

        // 返回一个店铺对应的所有信息
        List<ShopCartExpiryItemDTO> shopCartExpiryItems = Lists.newArrayList();

        for (Long key : shopCartItemDtoMap.keySet()) {
            ShopCartExpiryItemDTO shopCartExpiryItemDto = new ShopCartExpiryItemDTO();
            shopCartExpiryItemDto.setShopId(key);
            List<ShopCartItemDTO> shopCartItemDTOList = Lists.newArrayList();
            for (ShopCartItemDTO tempShopCartItemDto : shopCartItemDtoMap.get(key)) {
                shopCartExpiryItemDto.setShopName(tempShopCartItemDto.getShopName());
                shopCartExpiryItemDto.setShopAvatar(tempShopCartItemDto.getShopAvatar());
                shopCartItemDTOList.add(tempShopCartItemDto);
            }
            shopCartExpiryItemDto.setShopCartItemDtoList(shopCartItemDTOList);
            shopCartExpiryItems.add(shopCartExpiryItemDto);
        }

        return R.ok(shopCartExpiryItems);
    }

    @ApiOperationSupport(order = 4)
    @DeleteMapping("/cleanExpiryProdList")
    @Operation(summary = "清空用户失效产品" , description = "清空用户失效产品")
    public R cleanExpiryProdList() {
        Long userId = SecurityUtils.getUser().getId();
        cartService.cleanExpiryProdList(userId);
        return R.ok();
    }

    @ApiOperationSupport(order = 5)
    @PostMapping("/totalPay")
    @Operation(summary = "获取选中购物项总计、选中的产品数量", description = "获取选中购物项总计、选中的产品数量,参数为购物车id数组")
    public R<ShopCartAmountDTO> getTotalPay(@RequestBody List<Long> cartIds) {

        // 拿到购物车的所有item
        List<ShopCartItemDTO> shopCartItems = cartService.getShopCartItems(SecurityUtils.getUser().getId());

        List<ShopCartItemDTO> chooseShopCartItems = shopCartItems
                .stream()
                .filter(shopCartItemDto -> {
                    for (Long cartId : cartIds) {
                        if (Objects.equals(cartId, shopCartItemDto.getCartId())) {
                            return true;
                        }
                    }
                    return false;
                })
                .collect(Collectors.toList());

        // 根据店铺ID划分item
        Map<Long, List<ShopCartItemDTO>> shopCartMap = chooseShopCartItems.stream().collect(Collectors.groupingBy(ShopCartItemDTO::getShopId));

        int count = 0;
        BigDecimal total = BigDecimal.ZERO;
        BigDecimal reduce = BigDecimal.ZERO;
        for (Long shopId : shopCartMap.keySet()) {
            // 获取店铺的所有产品项
            List<ShopCartItemDTO> shopCartItemDtoList = shopCartMap.get(shopId);
            // 构建每个店铺的购物车信息
            ShopCartDTO shopCart = new ShopCartDTO();
            shopCart.setShopId(shopId);

            applicationContext.publishEvent(new ShopCartEvent(shopCart, shopCartItemDtoList));

            for (ShopCartItemDiscountDTO shopCartItemDiscount : shopCart.getShopCartItemDiscounts()) {
                for (ShopCartItemDTO shopCartItem : shopCartItemDiscount.getShopCartItems()) {
                    count = shopCartItem.getProdNum() + count;
                    total = NumberUtil.add(shopCartItem.getTotalAmount(), total);
                }
            }
        }
        ShopCartAmountDTO shopCartAmountDto = new ShopCartAmountDTO();
        shopCartAmountDto.setCount(count);
        shopCartAmountDto.setTotalMoney(total);
        shopCartAmountDto.setSubtractMoney(reduce);
        shopCartAmountDto.setFinalMoney(NumberUtil.sub(shopCartAmountDto.getTotalMoney(), shopCartAmountDto.getSubtractMoney()));

        return R.ok(shopCartAmountDto);
    }

    @ApiOperationSupport(order = 6)
    @Operation(summary = "删除购物车", description = "通过购物车id删除用户购物车物品")
    @DeleteMapping
    public R remove(@RequestBody List<Long> cartIds) {
        if (CollUtil.isEmpty(cartIds)) {
            return R.ok();
        }
        Long userId = SecurityUtils.getUser().getId();
        cartService.removeShopCartItemsByCartIds(userId, cartIds);
        return R.ok();
    }

    @ApiOperationSupport(order = 7)
    @Operation(summary = "清空购物车", description = "清空用户购物车所有物品")
    @DeleteMapping("/clear")
    public R removeAll() {
        Long userId = SecurityUtils.getUser().getId();
        cartService.removeAllShopCartItems(userId);
        return R.ok();
    }

}
